<?php

namespace Biz\module\Classes\wiki;

use Biz\cache\wiki\LastRelateUids;
use Biz\cache\wiki\LastRelateUidsOfCategory;
use Biz\model\Album\AlbumWikiListModel;
use Biz\model\wiki\ObjRelateWiki as mObjRelateWiki;
use Biz\model\wiki\Wiki as mWiki;
use Biz\model\wiki\WikiList as mWikiList;
use Biz\pockets\serviceTrait\_Async;
use Doraemon\cache\ArticleCounter;
use Doraemon\cache\BlankCounter;
use Doraemon\cache\GuideCounter;
use Doraemon\cache\PhotoCounter;
use Doraemon\cache\Queue;
use Doraemon\cache\UserCounter;
use Doraemon\model\Pics;
use Doraemon\service\Article as sArticle;
use Doraemon\service\Guide as sGuide;
use Doraemon\tools\Log;

class RelateWiki
{
    use _Async;

    const MAX_RELATE_WIKI = 100;

    public static function objRelateWiki($uid, $objId, $objType, $relObjId, $relObjType, array $wikiIds, $type = mObjRelateWiki::TYPE_USER_REL, $addTime = null)
    {
        $logArr = [
            'uid' => $uid,
            'obj_id' => $objId,
            'obj_type' => $objType,
            'rel_obj_id' => $relObjId,
            'rel_obj_type' => $relObjType,
            'wiki_ids' => $wikiIds,
            'type' => $type
        ];
        $logStr = $objId . '#' . mObjRelateWiki::$objTypeDesc[$objType] . '#' . $relObjId . "#关联wiki#";
        Log::wiki_relateObj_info($logStr . "data:" . json_encode($logArr));
        if (!$uid || !$objId || !$objType) {
            Log::wiki_relateObj_warning($logStr . '#参数错误#' . "data:" . json_encode($logArr));
            throw new \Exception('参数错误');
        }
        $allRelateWikiIds = mObjRelateWiki::getAllRelateWikIds($objId, $objType, $relObjId, $relObjType);
        Log::wiki_relateObj_info($logStr . "已经关联的wiki Id:" . json_encode($allRelateWikiIds));
        if (!self::checkRelateWikiCount($objType, $relObjType, $allRelateWikiIds, $wikiIds)) {
            Log::wiki_relateObj_info($logStr . "关联数量不能超过:" . self::MAX_RELATE_WIKI . '#data:' . json_encode($logArr));
            throw new \Exception('最多只能关联' . self::MAX_RELATE_WIKI . '个wiki');
        }
        $hasWikiIds = mWiki::hasWikiIds($wikiIds);
        $relateList = [];
        if ($wikiIds) {
            $relateList = mObjRelateWiki::getByWhere([
                'obj_id' => $objId,
                'obj_type' => $objType,
                'rel_obj_id' => $relObjId,
                'rel_obj_type' => $relObjType,
                'wiki_id' => $wikiIds,
            ]);
        }
        $wikiRelateList = [];
        foreach ($relateList as $row) {
            $wikiRelateList[$row['wiki_id']][] = $row;
        }
        $afterRelateWikiIds = $wikiIds;
        $delWikiIds = [];
        if (!empty($allRelateWikiIds)) {
            $delWikiIds = array_diff($allRelateWikiIds, $wikiIds);
            $afterRelateWikiIds = array_merge($wikiIds, $delWikiIds);
        }
        $result = mObjRelateWiki::action(function () use ($uid, $objId, $objType, $relObjId, $relObjType, $wikiIds, $type, $addTime, $allRelateWikiIds, $delWikiIds, $hasWikiIds, $wikiRelateList, $logStr, $logArr) {
            $result = true;
            foreach ($wikiIds as $wikiId) {
                if (!isset($hasWikiIds[$wikiId])) {
                    throw new \Exception('wiki不存在');
                }
                $wikiRelate = isset($wikiRelateList[$wikiId]) ? $wikiRelateList[$wikiId] : [];
                $result = self::addObjRelate($wikiRelate, $wikiId, $objId, $objType, $relObjId, $relObjType, $uid, $type, $addTime);
                if (!$result) {
                    return false;
                }
            }
            if (!empty($delWikiIds)) {
                Log::wiki_relateObj_info($logStr . "取消关联的wikiIds:" . json_encode($delWikiIds));
                if ($delWikiIds) {
                    $where = [];
                    $where['obj_id'] = $objId;
                    $where['obj_type'] = $objType;
                    $where['rel_obj_id'] = $relObjId;
                    $where['rel_obj_type'] = $relObjType;
                    $where['wiki_id'] = $delWikiIds;
                    $where['uid'] = $uid;
                    $where['type'] = $type;
                    $result = mObjRelateWiki::updateData(['status' => mObjRelateWiki::STATUS_CLOSE], $where);
                }
            }
            return $result;
        });
        if (!$result) {
            Log::wiki_relateObj_warning($logStr . '关联wiki信息失败#data:' . json_encode($logArr));
            \Doraemon\amqp\Queue::insertQueue("queue/Wechatnotice/toTag", [
                "totag" => \Biz\pockets\constInterface\BizWechatTagConfig::TAG_BIZ_RD_SYSTEM,
                "content" => $logStr . '关联wiki信息失败#data:' . json_encode($logArr)
            ], Queue::QUEUE_BIZ);
        }
        self::afterRelateWiki($uid, $afterRelateWikiIds, $objId, $objType);
        return $result;
    }

    /**
     * 直接关联wiki（只关联传入的wiki，不做删除处理）
     * @param $uid
     * @param $objId
     * @param $objType
     * @param $relObjId
     * @param $relObjType
     * @param array $wikiIds
     * @param int $type
     * @param null $addTime
     * @throws \Exception
     */
    public static function addRelateWiki($uid, $objId, $objType, $relObjId, $relObjType, array $wikiIds, $type = mObjRelateWiki::TYPE_USER_REL, $addTime = null)
    {
        $logArr = [
            'uid' => $uid,
            'obj_id' => $objId,
            'obj_type' => $objType,
            'rel_obj_id' => $relObjId,
            'rel_obj_type' => $relObjType,
            'wiki_ids' => $wikiIds,
            'type' => $type
        ];
        $logStr = $objId . '#' . mObjRelateWiki::$objTypeDesc[$objType] . '#' . $relObjId . "#关联wiki#";
        if (!$uid || !$objId || !$objType) {
            Log::wiki_relateObj_warning($logStr . '#参数错误#' . "data:" . json_encode($logArr));
            throw new \Exception('参数错误');
        }
        $hasWikiIds = mWiki::hasWikiIds($wikiIds);
        $relateList = mObjRelateWiki::getByWhere([
            'obj_id' => $objId,
            'obj_type' => $objType,
            'rel_obj_id' => $relObjId,
            'rel_obj_type' => $relObjType,
            'wiki_id' => $wikiIds,
        ]);
        $wikiRelateList = [];
        foreach ($relateList as $row) {
            $wikiRelateList[$row['wiki_id']][] = $row;
        }
        foreach ($wikiIds as $wikiId) {
            if (!isset($hasWikiIds[$wikiId])) {
                throw new \Exception('wiki不存在');
            }
            $wikiRelate = isset($wikiRelateList[$wikiId]) ? $wikiRelateList[$wikiId] : [];
            $result = self::addObjRelate($wikiRelate, $wikiId, $objId, $objType, $relObjId, $relObjType, $uid, $type, $addTime);
            if (!$result) {
                Log::wiki_relateObj_warning($logStr . '#关联失败#' . "data:" . json_encode($logArr));
            }
        }
        self::afterRelateWiki($uid, $wikiIds, $objId, $objType);
    }

    public static function addObjRelate($wikiRelate, $wikiId, $objId, $objType, $relObjId, $relObjType, $uid, $type, $addTime = null)
    {
        $addTime = empty($addTime) ? date('Y-m-d H:i:s') : $addTime;
        $result = true;
        if ($wikiId) {
            if ($wikiRelate) {
                foreach ($wikiRelate as $row) {
                    if ($row['status'] != mObjRelateWiki::STATUS_NORMAL) {
                        $result = mObjRelateWiki::updateData([
                            'uid' => $uid,
                            'type' => $type,
                            'status' => mObjRelateWiki::STATUS_NORMAL,
                            'addtime' => $addTime,
                        ], [
                                'obj_id' => $objId,
                                'obj_type' => $objType,
                                'rel_obj_id' => $relObjId,
                                'rel_obj_type' => $relObjType,
                                'wiki_id' => $wikiId
                            ]
                        );
                    }
                }
            } else {
                $result = mObjRelateWiki::insertData([
                    'obj_id' => $objId,
                    'obj_type' => $objType,
                    'rel_obj_id' => $relObjId,
                    'rel_obj_type' => $relObjType,
                    'wiki_id' => $wikiId,
                    'uid' => $uid,
                    'type' => $type,
                    'addtime' => $addTime,
                    'status' => mObjRelateWiki::STATUS_NORMAL,
                ]);
                if ($result) {
                    $result = mObjRelateWiki::id();
                }
            }
        }
        return $result;
    }

    /**
     * 删除内容关联wiki
     * @param $uid
     * @param $objId
     * @param $objType
     * @param null $relObjId
     * @param null $relObjType
     * @param null $wikiId
     * @param null $type
     * @throws \Exception
     */
    public static function delRelateWiki($uid, $objId, $objType, $relObjId = null, $relObjType = null, $wikiId = null, $type = null)
    {
        $where = [
            'uid' => $uid,
            'obj_id' => $objId,
            'obj_type' => $objType
        ];
        if (!is_null($relObjType)) {
            $where['rel_obj_type'] = $relObjType;
        }
        if (!is_null($relObjId)) {
            $where['rel_obj_id'] = $relObjId;
        }
        if (!is_null($wikiId)) {
            $where['wiki_id'] = $wikiId;
        }

        if (!is_null($type)) {
            $where['type'] = $type;
        }

        $result = mObjRelateWiki::updateData(['status' => mObjRelateWiki::STATUS_DEL], $where);
        if ($result) {
            unset($where['wiki_id']);
            unset($where['type']);
            $wikiIds = mObjRelateWiki::getByWhere($where, 'wiki_id');
            $wikiIds = array_unique(array_filter($wikiIds));
            self::afterRelateWiki($uid, $wikiIds, $objId, $objType);
        } else {
            throw new \Exception('删除wiki关联失败');
        }
    }

    private static function checkRelateWikiCount($objType, $relObjType, $allRelateWikiIds, $wikiIds)
    {
        $result = true;
        $checker = false;
        if ($objType == mObjRelateWiki::OBJ_TYPE_NOTE && $relObjType != mObjRelateWiki::REL_OBJ_TYPE_COMMENT) {//note
            $checker = true;
        }
        if ($objType == mObjRelateWiki::OBJ_TYPE_BLANK && $relObjType == 0) {//文章，用户自己关联wiki
            $checker = true;
        }
        if ($checker) {
            $delWikiIds = array_diff($allRelateWikiIds, $wikiIds);
            $addWikiIds = array_diff($wikiIds, $allRelateWikiIds);
            if ($allRelateWikiIds) {
                $count = count($allRelateWikiIds) - count($delWikiIds) + count($addWikiIds);
            } else {
                $count = count($wikiIds);
            }
            $result = ($count <= self::MAX_RELATE_WIKI);
        }
        return $result;
    }

    /**
     * 关联wiki后的操作
     * @param $uid
     * @param array $wikiIds
     * @param $objId
     * @param $objType
     */
    public static function afterRelateWiki($uid, array $wikiIds, $objId, $objType)
    {
        Log::wiki_afterRelate_info(json_encode(['uid' => $uid, 'obj_id' => $objId, 'obj_type' => $objType, 'wiki_ids' => $wikiIds]));
        //更新wiki list
        self::changeUserWikiList($uid);
        ////更新关联wiki数量
        foreach ($wikiIds as $wikiId) {
            self::changeWikiRelateNum($wikiId);
        }
        //更新整屋wiki
        $rela_pic_list = Pics::getRelaArticlePicsByNoteId($objId);
        if ($rela_pic_list) {
            foreach ($rela_pic_list as $pic_item) {
                RelateWiki::setWikisNumByObjId($pic_item['article_id'], mObjRelateWiki::OBJ_TYPE_ARTICLE);
            }
        }
        self::setWikisNumByObjId($objId, $objType);

        self::updateLastRelateUid($uid, $wikiIds);
    }

    /**
     * 更新用户wiki清单
     * @param $uid
     */
    public static function changeUserWikiList($uid)
    {
        self::_async($uid);
    }

    public static function _async_changeUserWikiList($uid)
    {
        $wikiList = mWikiList::selectByWhere(['uid' => $uid], '*');
        $userAllWikiList = [];//用户全部wiki清单，包括删除的
        $userAllNormalWikiList = [];//用户全部正常的wiki清单
        foreach ($wikiList as $row) {
            $userAllWikiList[] = $row['wiki_id'];
            if ($row['status'] == mWikiList::STATUS_NORMAL) {
                $userAllNormalWikiList[] = $row['wiki_id'];
            }
        }

        $userRelatedWikiIds = mObjRelateWiki::getByWhere(['uid' => $uid, 'status' => mObjRelateWiki::STATUS_NORMAL, 'wiki_id[!]' => 0], 'wiki_id');
        $userAlbumRelatedWikiIds = AlbumWikiListModel::selectByWhere(['uid' => $uid, 'status' => AlbumWikiListModel::STATUS_NORMAL], 'wiki_id');

        $delWikiIds = array_diff($userAllWikiList, array_unique(array_merge($userRelatedWikiIds,$userAlbumRelatedWikiIds)));
        if ($delWikiIds) {
            Log::wiki_changeUserWikiList_info("uid:" . $uid . "需要从清单移除的wikiIds：" . json_encode($delWikiIds));
            mWikiList::updateData(['status' => mWikiList::STATUS_CLOSE], ['uid' => $uid, 'wiki_id' => $delWikiIds]);
        }
        $addWikiIds = array_diff(array_unique(array_merge($userRelatedWikiIds,$userAlbumRelatedWikiIds)), $userAllNormalWikiList);
        if ($addWikiIds) {
            Log::wiki_changeUserWikiList_info("uid:" . $uid . "需要添加到清单的wikiIds：" . json_encode($addWikiIds));
            foreach ($addWikiIds as $wikiId) {
                $has = mWikiList::has_master(['uid' => $uid, "wiki_id" => $wikiId]);
                if ($has) {
                    $result = mWikiList::updateData(['addtime' => date('Y-m-d H:i:s'), 'status' => mWikiList::STATUS_NORMAL], ['uid' => $uid, 'wiki_id' => $wikiId]);
                } else {
                    $result = mWikiList::insertData(['uid' => $uid, 'wiki_id' => $wikiId, 'addtime' => date('Y-m-d H:i:s'), 'status' => mWikiList::STATUS_NORMAL]);
                }
            }
        }
        $count = mWikiList::getUserWikiCount($uid);
        UserCounter::setCounter($uid, [UserCounter::TYPE_RELATE_WIKI => $count]);
    }

    public static function changeWikiRelateNum($wikiId)
    {
        if ($wikiId) {
            self::_async($wikiId);
        }
    }

    public static function _async_changeWikiRelateNum($wikiId)
    {
        $num = mObjRelateWiki::getWikiRelateCount($wikiId);
        
        $obj_last_relate_time= \Biz\service\wiki\ObjRelateWiki::getLastWikiRelateTime($wikiId) ?? 0;

        mWiki::updateData(['relate_num' => $num , 'obj_last_relate_time'=>$obj_last_relate_time], ['id' => $wikiId]);
    }

    /**
     * 设置内容关联的wiki数量
     * @param $objId
     * @param $objType
     */
    public static function setWikisNumByObjId($objId, $objType)
    {
        if ($objId && $objType) {
            self::_async($objId, $objType);
        }
    }

    public static function _async_setWikisNumByObjId($objId, $objType)
    {
        $count = self::getObjCount($objId, $objType);
        if ($objType == mObjRelateWiki::OBJ_TYPE_NOTE) {//note
            PhotoCounter::setWikisNumByPhotoid($objId, $count);
        } else if ($objType == mObjRelateWiki::OBJ_TYPE_BLANK) {//文章
            BlankCounter::setWikiNumById($objId, $count);
        } else if ($objType == mObjRelateWiki::OBJ_TYPE_ARTICLE) {//整屋 整屋下所有note数量和整屋评论的数量
            ArticleCounter::setWikisNumByArticleId($objId, $count);
            Queue::insertQueue('Article/updateSolr', array(
                'article_id' => $objId
            ));//更新整屋Solr
        } else if ($objType == mObjRelateWiki::OBJ_TYPE_GUIDE) {//指南
            GuideCounter::setWikisNumByGuidId($objId, $count);
        }
        Log::wiki_setObjWikisNum_info(json_encode(['obj_id' => $objId, 'obj_type' => $objType, 'count' => $count]));
    }

    public static function getObjCount($objId, $objType)
    {
        $wikiIds = [];
        switch ($objType) {
            case mObjRelateWiki::OBJ_TYPE_NOTE://note
            case mObjRelateWiki::OBJ_TYPE_BLANK://文章
                $wikiIds = self::getObjWikiIds($objId, $objType);
                break;
            case mObjRelateWiki::OBJ_TYPE_GUIDE://指南
                $wikiIds = self::getObjWikiIds($objId, $objType);
                $noteIds = sGuide::getRelativNoteIds($objId);
                if ($noteIds) {
                    $noteWikiIds = self::getObjWikiIds($noteIds, mObjRelateWiki::OBJ_TYPE_NOTE);
                    $wikiIds = array_merge($wikiIds, $noteWikiIds);
                    $wikiIds = array_unique($wikiIds);
                }
                break;
            case mObjRelateWiki::OBJ_TYPE_ARTICLE://整屋 整屋下所有note数量和整屋评论的数量
                $wikiIds = self::getObjWikiIds($objId, $objType);
                $noteIds = sArticle::getRelaNoteIds($objId);
                if ($noteIds) {
                    $noteWikiIds = self::getObjWikiIds($noteIds, mObjRelateWiki::OBJ_TYPE_NOTE);
                    $wikiIds = array_merge($wikiIds, $noteWikiIds);
                    $wikiIds = array_unique($wikiIds);
                }
                break;
        }
        $wikiIds = array_unique($wikiIds);
        $count = count($wikiIds);
        return $count;
    }

    public static function getObjWikiIds($objId, $objType)
    {
        $wikiIds = [];
        if (!is_array($objId)) {
            $objId = array($objId);
        }
        $list = mObjRelateWiki::getByWhere(['obj_id' => $objId, 'obj_type' => $objType, 'status' => mObjRelateWiki::STATUS_NORMAL, 'wiki_id[>]' => 0], ['obj_id', 'wiki_id']);
        $objWikiIds = [];
        foreach ($list as $row) {
            if (!isset($objWikiIds[$row['obj_id']])) {
                $objWikiIds[$row['obj_id']][] = $row['wiki_id'];
            }
            if (!in_array($row['wiki_id'], $objWikiIds[$row['obj_id']])) {
                $objWikiIds[$row['obj_id']][] = $row['wiki_id'];
            }
        }
        foreach ($objWikiIds as $objId => $row) {
            foreach ($row as $wikiId) {
                array_push($wikiIds, $wikiId);
            }
        }
        $wikiIds = array_unique($wikiIds);
        return $wikiIds;
    }


    /**
     * 最后关联wiki的uid，存redis
     * @param $uid
     * @param $wikiIds
     */
    public static function updateLastRelateUid($uid, $wikiIds)
    {
        if (!empty($wikiIds) && !empty($uid)) {
            self::_async($uid, $wikiIds);
        }
    }

    public static function _async_updateLastRelateUid($uid, $wikiIds)
    {
        $relList = mObjRelateWiki::select('*', [
            'wiki_id' => $wikiIds,
            'uid' => $uid,
        ]);
        $list = mWiki::selectByWhere(['id' => $wikiIds], ['id', 'status', 'category_id', 'second_category_id', 'third_category_id', 'four_category_id']);
        $wikiList = [];
        foreach ($list as $row) {
            $wikiList[$row['id']] = $row;
            if ($row['status'] == mWiki::STATUS_DEL) {//如果wiki删除状态，需求删除wiki的缓存
                LastRelateUids::delWikiAllRel($row['id']);
                if ($row['category_id'] > 0) {
                    LastRelateUidsOfCategory::delCategoryAllRel($row['category_id']);
                }
                if ($row['second_category_id'] > 0) {
                    LastRelateUidsOfCategory::delCategoryAllRel($row['second_category_id']);
                }
                if ($row['third_category_id'] > 0) {
                    LastRelateUidsOfCategory::delCategoryAllRel($row['third_category_id']);
                }
                if ($row['four_category_id'] > 0) {
                    LastRelateUidsOfCategory::delCategoryAllRel($row['four_category_id']);
                }
            }
        }
        foreach ($relList as $row) {
            if ($row['status'] == mObjRelateWiki::STATUS_NORMAL) {
                $wikiId = $row['wiki_id'];
                $time = strtotime($row['addtime']);
                $wikiInfo = [];
                if (isset($wikiList[$wikiId]) && $wikiList[$wikiId] && $wikiList[$wikiId]['status'] != mWiki::STATUS_DEL) {
                    $wikiInfo = $wikiList[$wikiId];
                }
                if ($wikiInfo) {
                    LastRelateUids::addLastUid($wikiId, $uid, $time);
                    if ($wikiInfo['category_id'] > 0) {
                        LastRelateUidsOfCategory::addLastUid($wikiInfo['category_id'], $uid, $time);
                    }
                    if ($wikiInfo['second_category_id'] > 0) {
                        LastRelateUidsOfCategory::addLastUid($wikiInfo['second_category_id'], $uid, $time);
                    }
                    if ($wikiInfo['third_category_id'] > 0) {
                        LastRelateUidsOfCategory::addLastUid($wikiInfo['third_category_id'], $uid, $time);
                    }
                    if ($wikiInfo['four_category_id'] > 0) {
                        LastRelateUidsOfCategory::addLastUid($wikiInfo['four_category_id'], $uid, $time);
                    }
                }
            }
        }
    }

}